package monitoring

import (
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"fmt"
	"github.com/shirou/gopsutil/v3/mem"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
	"unsafe"
)

// 总内存使用率
var memoryUsageRate float64 = 0
var m, _ = mem.VirtualMemory()

// 默认内存限制16G
var MemoryLimit = 16 * 1024 * 1024 * 1024

func init() {
	//go memoryMonitoring()
}

func memoryMonitoring() {
	var timeNum = 0
	// 计算所有线程的内存大小
	var beforeMemorySize = GetThreadStoresAllMemory()
	time.Sleep(time.Second * 120) // 120秒后开启内存监控
	//上次内存
	for {
		m, _ = mem.VirtualMemory()      //更新内存
		memoryUsageRate = m.UsedPercent // 内存使用率
		//判断,之前的内存和现在的内存差值，如果大于100m，那么就会触发清理
		var nowMemorySize = GetThreadStoresAllMemory()
		//每10分钟打印一次内存使用情况
		if timeNum == 20 {
			printMemoryInfo()
			MemoryAnalysis()
			timeNum = 0
		}
		if nowMemorySize-beforeMemorySize > 100*1024*1024 {
			fmt.Println("累积内存使用超过100M,开始清理，清理前内存大小:", beforeMemorySize, "清理后内存大小:", nowMemorySize)
			//CleanInstance()
			//CleanTypeDefaultInstance()
			beforeMemorySize = GetThreadStoresAllMemory()
		}
		//如果内存使用大于16G,那么就会触发宕机
		if int(nowMemorySize) > MemoryLimit {
			fmt.Println("本程序内存使用大于16G,超过了默认内存限制,程序关闭")
			printMemoryInfo()
			MemoryAnalysis()
			//打印目前系统内没有被删除的
			os.Exit(1) //退出程序
		}

		//总内存使用率大于95,会触发宕机
		if memoryUsageRate > 95 {
			fmt.Println("系统总内存使用率大于95,内存不够用了,程序关闭")
			printMemoryInfo()
			MemoryAnalysis()
			//打印目前系统内没有被删除的
			os.Exit(1) //退出程序
		}
		time.Sleep(time.Second * 30) // 30秒钟监控一次
		timeNum++
	}
}

// 打印内存信息
func printMemoryInfo() {
	//内存当前使用情况打印
	fmt.Printf("当前系统总内存信息:  内存总量:%v,内存使用率:%v,内存使用量:%v,内存剩余量:%v\n", m.Total, m.UsedPercent, m.Used, m.Free)
}

// 计算单个线程的内存使用
func GetThreadStoreMemory(threadStore *structdef.ThreadStore) uintptr {
	wg := sync.WaitGroup{}
	wg.Add(4)
	sizeof := unsafe.Sizeof(*threadStore)
	var sizeof1 uintptr
	var sizeof2 uintptr
	var sizeof3 uintptr
	var sizeof4 uintptr
	//计算变量存储的内存
	go func() {
		for key, value := range threadStore.VariableStoreMap {
			sizeof1 += unsafe.Sizeof(key)
			sizeof1 += unsafe.Sizeof(value)
			for key1, value1 := range value {
				sizeof1 += unsafe.Sizeof(key1)
				sizeof1 += unsafe.Sizeof(value1)
			}
		}
		sizeof += sizeof1
		wg.Done()
	}()

	go func() {
		//计算实例存储的内存
		for key, value := range threadStore.InstanceStore {
			sizeof2 += unsafe.Sizeof(key)
			sizeof2 += unsafe.Sizeof(value)
			for key1, value1 := range value {
				sizeof2 += unsafe.Sizeof(key1)
				sizeof2 += unsafe.Sizeof(value1)
			}
		}
		sizeof += sizeof2
		wg.Done()
	}()

	go func() {
		//计算默认实例存储的内存
		for key, value := range threadStore.TypeDefaultInstanceStore {
			sizeof3 += unsafe.Sizeof(key)
			sizeof3 += unsafe.Sizeof(value)
			for key1, value1 := range value {
				sizeof3 += unsafe.Sizeof(key1)
				sizeof3 += unsafe.Sizeof(value1)
			}
		}
		sizeof += sizeof3
		wg.Done()
	}()

	go func() {
		//计算默认实例反向存储的内存
		for key, value := range threadStore.TypeDefaultInstanceInversionStore {
			sizeof4 += unsafe.Sizeof(key)
			sizeof4 += unsafe.Sizeof(value)
		}
		sizeof += sizeof4

		//计算代码执行记录的内存
		for _, value := range threadStore.ExecuteCodeRecordLogMap {
			sizeof4 += unsafe.Sizeof(value)
		}
		//计算代码执行时间的内存
		for key, value := range threadStore.MapCodeTime {
			sizeof4 += unsafe.Sizeof(key)
			sizeof4 += unsafe.Sizeof(value)
			for key1, value1 := range value {
				sizeof4 += unsafe.Sizeof(key1)
				sizeof4 += unsafe.Sizeof(value1)
			}
		}
		sizeof += sizeof4
		wg.Done()
	}()
	wg.Wait()
	//汇总
	sizeof += sizeof1 + sizeof2 + sizeof3 + sizeof4
	return sizeof
}

// 计算所有线程的内存使用总和
func GetThreadStoresAllMemory() uintptr {
	var memorySize uintptr = 0
	var list = utils.NewSyncSlice[uintptr]()
	wg := sync.WaitGroup{}
	store.ThreadStoreMap.Range(func(key string, value *structdef.ThreadStore) bool {
		wg.Add(1)
		go func() {
			sizeof := GetThreadStoreMemory(value)
			list.Add(sizeof)
		}()
		return true
	})
	wg.Wait()
	list.Range(func(index int, value uintptr) bool {
		memorySize += value
		return true
	})
	return memorySize
}

// 找出最大内存使用的线程
func GetThreadStoresMaxMemory() *structdef.ThreadStore {
	var maxMemorySize uintptr = 0
	var maxMemoryStore *structdef.ThreadStore
	var list = utils.NewSyncSlice[string]()
	wg := sync.WaitGroup{}
	store.ThreadStoreMap.Range(func(key string, value *structdef.ThreadStore) bool {
		wg.Add(1)
		go func() {
			sizeof := GetThreadStoreMemory(value)
			list.Add(strconv.Itoa(int(sizeof)) + "@" + value.ThreadId)
		}()
		return true
	})
	wg.Wait()
	//找出最大的内存使用
	list.Range(func(index int, value string) bool {
		split := strings.Split(value, "@")
		size, _ := strconv.Atoi(split[0])
		if uintptr(size) > maxMemorySize {
			maxMemorySize = uintptr(size)
			maxMemoryStore = store.GetThreadStore(split[1])
		}
		return true
	})
	return maxMemoryStore
}

// 打印指定线程的内存使用情况
func PrintThreadStoreMemory(thread *structdef.ThreadStore) {
	wg := sync.WaitGroup{}
	wg.Add(3)
	var variableStoreMap uintptr = 0
	go func() {
		//计算变量存储的内存
		for key, value := range thread.VariableStoreMap {
			variableStoreMap += unsafe.Sizeof(key)
			variableStoreMap += unsafe.Sizeof(value)
			for key1, value1 := range value {
				variableStoreMap += unsafe.Sizeof(key1)
				variableStoreMap += unsafe.Sizeof(value1)
			}
		}
	}()
	var instanceStore uintptr = 0
	go func() {
		//计算实例存储的内存
		for key, value := range thread.InstanceStore {
			instanceStore += unsafe.Sizeof(key)
			instanceStore += unsafe.Sizeof(value)
			for key1, value1 := range value {
				instanceStore += unsafe.Sizeof(key1)
				instanceStore += unsafe.Sizeof(value1)
			}
		}
	}()
	var typeDefaultInstanceStore uintptr = 0
	go func() {
		for key, value := range thread.TypeDefaultInstanceStore {
			typeDefaultInstanceStore += unsafe.Sizeof(key)
			typeDefaultInstanceStore += unsafe.Sizeof(value)
			for key1, value1 := range value {
				typeDefaultInstanceStore += unsafe.Sizeof(key1)
				typeDefaultInstanceStore += unsafe.Sizeof(value1)
			}
		}
	}()
	total := GetThreadStoresAllMemory() //总大小

	wg.Wait()

	fmt.Printf("线程id:%s,线程内存总使用:%d, 变量内存使用:%d ,实例内存使用:%d ,默认实例内存使用:%d ,其他元数据内存使用%d \n",
		thread.ThreadId, total, variableStoreMap, instanceStore, typeDefaultInstanceStore, total-(variableStoreMap-instanceStore-typeDefaultInstanceStore))

}

func MemoryAnalysis() {
	fmt.Println("所有线程内存使用总和:", GetThreadStoresAllMemory())
	fmt.Println("最大内存使用线程:")
	PrintThreadStoreMemory(GetThreadStoresMaxMemory())
	//内存说明
	fmt.Println("每个线程内存使用情况:")
	for i := range store.GetThreadStores() {
		PrintThreadStoreMemory(store.GetThreadStores()[i])
	}

}
